const PENGING = "pengding";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {
  #state = PENGING;
  #result = undefined;
  #handlers = [];
  constructor(executor) {
    const resolve = (data) => {
      this.#changeState(FULFILLED, data);
    };
    const reject = (reason) => {
      this.#changeState(REJECTED, reason);
    };
    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  #changeState(state, result) {
    this.#state = state;
    this.#result = result;
  }
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this.#handlers.push({
        onFulfilled,
        onRejected,
        resolve,
        reject,
      });
      this.#run();
    });
  }
  #isPromiseLike(value) {
    if (
      value !== null &&
      (typeof value === "object" || typeof value === "function")
    ) {
      return typeof value.then === "function";
    }
    return false;
  }
  #runMicroTask(func) {
    if (typeof process === "object" && typeof process.nextTick === "function") {
      process.nextTick(func);
    } else if (typeof MutationObserver === "function") {
      const ob = new MutationObserver(func);
      const textNode = document.createTextNode(1);
      ob.observe(textNode, {
        characterData: true,
      });
      textNode.data = 2;
    } else {
      setTimeout(func, 0);
    }
  }
  #runOne(callback, resolve, reject) {
    if (typeof callback !== "function") {
      const settled = this.#state === FULFILLED ? resolve : reject;
      settled(this.#result);
      return;
    }
    try {
      const data = callback(this.#result);
      if (this.#isPromiseLike(data)) {
        data.then(resolve, reject);
      } else {
        resolve(data);
      }
    } catch (err) {
      reject(err);
    }
  }
  #run() {
    if (this.#state === PENGING) return;
    while (this.#handlers.length) {
      const { onFulfilled, onRejected, resolve, reject } =
        this.#handlers.shift();
      if (this.#state === FULFILLED) {
        this.#runOne(onFulfilled, resolve, reject);
      } else {
        this.#runOne(onFulfilled, resolve, reject);
      }
    }
  }
}

const p = new MyPromise((resolve, reject) => {
  resolve("123");
});
p.then(
  (res) => {
    console.log("promise 完成", res);
  },
  (err) => {
    console.log("promise 失败", err);
  }
);

async function fetchData() {
  console.log("1111");
  await new Promise((resolve) => {
    console.log("22222");
    resolve();
  }).then(() => {
    console.log("33333");
  });
  console.log("44444");
  console.log("99999");
}
console.log("88888");
fetchData();
new Promise((resolve) => {
  console.log("55555");
  resolve();
})
  .then(() => {
    console.log("66666");
  })
  .then(() => {
    console.log("121212");
  });

setTimeout(() => {
  console.log("77777");
}, 0);

setTimeout(() => {
  console.log("3333");
  new Promise((resolve) => {
    console.log("11111");
    resolve();
  }).then(() => {
    setTimeout(() => {
      console.log("22222");
    });
  });
});
